    # coding:utf-8

from old_version.src.util.HbaseUtil import HbaseUtil
from old_version.src.util.RedisUtil import RedisUtil
from old_version.src.util.ListUtil import ListUtil
from old_version.src.util.HttpUtil import HttpUtil
from old_version.src.util.StrUtil import StrUtil
from old_version.src import StockRecord
from old_version.src.util.TimeUtil import TimeUtil
import json

'''
StockRecord的服务类
'''


class StockRecordService:

    def __init__(self):
        pass
        # self.stock_record_object_list = None
        # self.distinct_stock_code_set = None

    '''
    初始化常用对象或列表
    '''
    # def update(self):
    #     self.stock_record_object_list = self.get_stock_record_object_list()
    #     self.distinct_stock_code_set = self.get_distinct_stock_code_set(self.stock_record_object_list)

    '''
    从网络上采集股票交易数据，首先存储在redis集群中，然后再存储在stock_record.json文件中
    参数write_file表示是否向文件中写数据
    '''
    def collect_stock_record(self, write_file):
        print(TimeUtil.date(), "collect_stock_record method start")
        stock_list = HbaseUtil.get_all_stock()
        stock_record_list = list()
        f = open("/stock_record.json", "a+")
        if ListUtil.is_not_empty(stock_list):
            for stock in stock_list:
                param = "code=1" + stock.code + "&start=20170102&end=20171229&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;CHG;PCHG;TURNOVER;VOTURNOVER;VATURNOVER;TCAP;MCAP"
                result = HttpUtil.get_data("http://quotes.money.163.com/service/chddata.html", param)
                row_list = result.split("\n")
                for index, name in enumerate(row_list):
                    # 第一行数据不采集
                    if index == 0:
                        continue
                    # 到达末尾就返回
                    if len(row_list) - 1 <= index:
                        break
                    column_list = name.split(",")
                    # column_list[11]是volume字段，如果是0，则表示停牌。停牌的数据不采集
                    if column_list[11].encode("utf-8") == "0":
                        continue

                    stock_record = StockRecord()
                    stock_record.id = (column_list[0].replace("-", "") + "_" + column_list[1][1:]).encode("utf-8")
                    stock_record.date = column_list[0].replace("-", "").encode("utf-8")
                    # the first char of code is ', so it should be deleted
                    stock_record.code = column_list[1][1:].encode("utf-8")
                    stock_record.name = column_list[2].encode("utf-8")
                    stock_record.close = column_list[3].encode("utf-8")
                    stock_record.high = column_list[4].encode("utf-8")
                    stock_record.low = column_list[5].encode("utf-8")
                    stock_record.open = column_list[6].encode("utf-8")
                    stock_record.last_close = column_list[7].encode("utf-8")
                    stock_record.up_down_amount = column_list[8].encode("utf-8")
                    stock_record.up_down = str(1) if stock_record.up_down_amount > str(0) else str(-1)
                    stock_record.up_down_percentage = column_list[9].encode("utf-8")
                    stock_record.turnover_rate = column_list[10].encode("utf-8")
                    stock_record.volume = column_list[11].encode("utf-8")
                    stock_record.amount = column_list[12].encode("utf-8")
                    stock_record.total_market_value = str(StrUtil.to_common_number(column_list[13]))
                    stock_record.circulation_market_value = str(StrUtil.to_common_number(column_list[14])).replace("\r",
                                                                                                                   "")
                    # 将stock_record对象保存在stock_record_list中，以便以后批量插入到redis集群中
                    stock_record_list.append(stock_record)
                    if write_file is True:
                        # 将stock_record对象装换为json字符串
                        json_str = json.dumps(stock_record.__dict__, encoding='UTF-8', ensure_ascii=False)
                        # 将stock_record的json字符串追加到文件stock_record.json中
                        f.write((json_str + "\n").encode("utf-8"))

        # 将stock_record_list数组批量加入到redis集群中
        RedisUtil.put_stock_record_list(stock_record_list)
        f.close()

    '''
    返回redis集群中的所有StockRecord类型的对象，并以list的形式返回。
    '''
    def get_stock_record_object_list(self):
        print(TimeUtil.date(), "get_stock_record_object_list method start")
        all_keys = RedisUtil.redis_conn.keys()
        if all_keys is None or len(all_keys) == 0:
            return None
        else:
            # 通过管道pipeline获取所有的value，每个value是字符串
            pipeline = RedisUtil.redis_conn.pipeline()
            for key in all_keys:
                pipeline.get(key)
            stock_record_list = pipeline.execute()

            # 将json字符串转换为StockRecord对象,并存储在stock_record_object_list列表中
            stock_record_object_list = list()
            for value in stock_record_list:
                stock_record_build = json.loads(value)
                stock_record = StockRecord()
                stock_record.__dict__ = stock_record_build
                stock_record_object_list.append(stock_record)
            return stock_record_object_list

    '''
    在stock_record_list数组中，根据code，对某一个股票按照时间(date)升序排列，并以list形式返回。
    '''
    def find_by_code_sort_by_date_asc(self, stock_record_list, code):
        # print(TimeUtil.date(), "find_by_code_sort_by_date_asc method start")
        if stock_record_list is None or len(stock_record_list) ==0:
            return None
        else:
            stock_record_list_by_code = list()
            # 根据code参数查找符合条件的StockRecord对象
            for stock_record in stock_record_list:
                if stock_record.code == code:
                    stock_record_list_by_code.append(stock_record)
            # 对stock_record_list_by_code数组，按照date（日期）进行升序排列
            if stock_record_list_by_code is not None and len(stock_record_list_by_code) > 0:
                count = len(stock_record_list_by_code)
                for i in range(0, count):
                    for j in range(i + 1, count):
                        if stock_record_list_by_code[i].date > stock_record_list_by_code[j].date:
                            stock_record_list_by_code[i], stock_record_list_by_code[j] = stock_record_list_by_code[j], stock_record_list_by_code[i]
                return stock_record_list_by_code

    '''
    从stock_record_list中，将每个stock_record的code属性组成一个set集合，并且set集合不能重复
    '''
    def get_distinct_stock_code_set(self, stock_record_list):
        print(TimeUtil.date(), "get_distinct_stock_code_set method start")
        if stock_record_list is not None and len(stock_record_list) > 0:
            stock_code_set = set()
            for stock_record in stock_record_list:
                stock_code_set.add(stock_record.code)
            return stock_code_set
        return None

    '''
    计算5日、10日、20日、60日、120日和240日均线
    '''
    def calculate_stock_average_close(self):
        print(TimeUtil.date(), "calculate_stock_average_close method start")
        all_stock_code = RedisUtil.redis_conn.keys("StockRecord_*")
        for stock_code in all_stock_code:
            single_stock_record_object_list = RedisUtil.redis_conn.zrange(stock_code, 0, -1, withscores=True)
            # single_stock_record_object_list = self.find_by_code_sort_by_date_asc(
            #     self.stock_record_object_list, stock_code)
            stock_close_list = list()
            for stock_record_str in single_stock_record_object_list:
                stock_record_build = json.loads(stock_record_str[0])
                stock_record_object = StockRecord()
                stock_record_object.__dict__ = stock_record_build
                stock_close_list.append(stock_record_object.close)
                stock_close_sum = float()
                # 临时对象，用来保存StockRecord类型的对象
                result_stock_record_object = stock_record_object

                # 注意：有时，有些股票的所有交易记录不足5条
                if len(stock_close_list) >= 5:
                    for element in stock_close_list[-5:]:
                        # 求5天收盘价的和
                        stock_close_sum = stock_close_sum + float(element.encode("utf-8"))
                    # 删除数组中的第一个元素，将其与4个元素向前挪一位，并删除下标为5的元素
                    # for i, element in enumerate(stock_close_list):
                    #     if i < len(stock_close_list) - 1:
                    #         stock_close_list[i] = stock_close_list[i + 1]
                    # 5天收盘价的平均值
                    five_average = stock_close_sum / 5
                    stock_close_sum = 0
                    # 向所有记录的five属性插入5天收盘价的平均值
                    result_stock_record_object.five = str(five_average)

                # 注意：有时，有些股票的所有交易记录不足10条
                if len(stock_close_list) >= 10:
                    for element in stock_close_list[-10:]:
                        # 求10天收盘价的和
                        stock_close_sum = stock_close_sum + float(element.encode("utf-8"))
                    # 删除数组中的第一个元素，将其与9个元素向前挪一位，并删除下标为10的元素
                    # for i, element in enumerate(stock_close_list):
                    #     if i < len(stock_close_list) - 1:
                    #         stock_close_list[i] = stock_close_list[i + 1]
                    # 10天收盘价的平均值
                    ten_average = stock_close_sum / 10
                    stock_close_sum = 0
                    # 向所有记录的ten属性插入10天收盘价的平均值
                    result_stock_record_object.ten = str(ten_average)

                # 注意：有时，有些股票的所有交易记录不足20条
                if len(stock_close_list) >= 20:
                    for element in stock_close_list[-20:]:
                        # 求20天收盘价的和
                        stock_close_sum = stock_close_sum + float(element.encode("utf-8"))
                    # 删除数组中的第一个元素，将其与19个元素向前挪一位，并删除下标20的元素
                    # for i, element in enumerate(stock_close_list):
                    #     if i < len(stock_close_list) - 1:
                    #         stock_close_list[i] = stock_close_list[i + 1]
                    # 20天收盘价的平均值
                    twenty_average = stock_close_sum / 20
                    stock_close_sum = 0
                    # 向所有记录的twenty属性插入20天收盘价的平均值
                    result_stock_record_object.twenty = str(twenty_average)

                # 注意：有时，有些股票的所有交易记录不足60条
                if len(stock_close_list) >= 60:
                    for element in stock_close_list[-60:]:
                        # 求60天收盘价的和
                        stock_close_sum = stock_close_sum + float(element.encode("utf-8"))
                    # 删除数组中的第一个元素，将其与59个元素向前挪一位，并删除下标60的元素
                    # for i, element in enumerate(stock_close_list):
                    #     if i < len(stock_close_list) - 1:
                    #         stock_close_list[i] = stock_close_list[i + 1]
                    # 60天收盘价的平均值
                    sixty_average = stock_close_sum / 60
                    stock_close_sum = 0
                    # 向所有记录的sixty属性插入60天收盘价的平均值
                    result_stock_record_object.sixty = str(sixty_average)

                # 注意：有时，有些股票的所有交易记录不足120条
                if len(stock_close_list) >= 120:
                    for element in stock_close_list[-120:]:
                        # 求120天收盘价的和
                        stock_close_sum = stock_close_sum + float(element.encode("utf-8"))
                    # 删除数组中的第一个元素，将其与119个元素向前挪一位，并删除下标120的元素
                    # for i, element in enumerate(stock_close_list):
                    #     if i < len(stock_close_list) - 1:
                    #         stock_close_list[i] = stock_close_list[i + 1]
                    # 120天收盘价的平均值
                    one_hundred_and_twenty_average = stock_close_sum / 120
                    stock_close_sum = 0
                    # 向所有记录的one_hundred_and_twenty属性插入120天收盘价的平均值
                    result_stock_record_object.one_hundred_and_twenty = str(one_hundred_and_twenty_average)

                # 注意：有时，有些股票的所有交易记录不足240条
                if len(stock_close_list) >= 240:
                    for element in stock_close_list[-240:]:
                        # 求240天收盘价的和
                        stock_close_sum = stock_close_sum + float(element.encode("utf-8"))
                    # 删除数组中的第一个元素，将其与39个元素向前挪一位，并删除下标240的元素
                    # for i, element in enumerate(stock_close_list):
                    #     if i < len(stock_close_list) - 1:
                    #         stock_close_list[i] = stock_close_list[i + 1]
                    # 240天收盘价的平均值
                    two_hundred_and_forty_average = stock_close_sum / 200
                    stock_close_sum = 0
                    # 向所有记录的two_hundred_and_forty属性插入240天收盘价的平均值
                    result_stock_record_object.two_hundred_and_forty = str(two_hundred_and_forty_average)

                new_json_str = json.dumps(result_stock_record_object.__dict__, encoding='UTF-8', ensure_ascii=False).encode("utf-8")
                # 经过json.dumps和json.loads方法后的json字符串虽然内容一样，但是顺序不一样了
                old_json_str = stock_record_str[0]
                RedisUtil.redis_conn.zrem("StockRecord_"+result_stock_record_object.code.encode("utf-8"), old_json_str)
                RedisUtil.redis_conn.zadd("StockRecord_"+result_stock_record_object.code.encode("utf-8"), result_stock_record_object.date.encode("utf-8"), new_json_str)

    '''
    计算MACD，其中包括初始化、ema12、ema26、dif和dea
    '''
    def calculate_stock_macd(self):
        print(TimeUtil.date(), "calculate_stock_macd method start")
        all_stock_code = RedisUtil.redis_conn.keys("StockRecord_*")
        if all_stock_code is not None and len(all_stock_code) > 0:
            for stock_code in all_stock_code:
                single_stock_record_object_list = RedisUtil.redis_conn.zrange(stock_code, 0, -1, withscores=True)

                # 初始化每只股票第一个交易日的ema12,ema26,dif和dea字段
                # 获取每只股票第一个交易日的对象
                stock_record_build = json.loads(single_stock_record_object_list[0][0])
                first_stock_record = StockRecord()
                first_stock_record.__dict__ = stock_record_build
                # first_stock_record = single_stock_record_object_list[0]
                first_stock_record.ema12 = first_stock_record.close
                first_stock_record.ema26 = first_stock_record.close
                first_stock_record.dif = str(0)
                first_stock_record.dea = str(0)
                new_json_str = json.dumps(first_stock_record.__dict__, encoding='UTF-8',
                                          ensure_ascii=False).encode("utf-8")
                # 经过json.dumps和json.loads方法后的json字符串虽然内容一样，但是顺序不一样了
                old_json_str = single_stock_record_object_list[0][0]
                # json_str = json.dumps(first_stock_record.__dict__, encoding='UTF-8', ensure_ascii=False)
                RedisUtil.redis_conn.zrem("StockRecord_"+first_stock_record.code.encode("utf-8"), old_json_str)
                RedisUtil.redis_conn.zadd("StockRecord_"+first_stock_record.code, first_stock_record.date, new_json_str)

                # 计算每只股票其余交易日的ema12,ema26,dif和dea字段
                # 用记录是第一个交易日的字段初始化相关变量
                pre_ema12 = first_stock_record.ema12
                pre_ema26 = first_stock_record.ema26
                pre_dif = first_stock_record.dif
                pre_dea = first_stock_record.dea
                for stock_record_tuple in single_stock_record_object_list[1:]:
                    stock_record_build = json.loads(stock_record_tuple[0])
                    stock_record = StockRecord()
                    stock_record.__dict__ = stock_record_build
                    stock_record.ema12 = str(float(pre_ema12.encode("utf-8")) * 11 / 13 + float(stock_record.close.encode("utf-8")) * 2 / 13)
                    stock_record.ema26 = str(float(pre_ema26.encode("utf-8")) * 25 / 27 + float(stock_record.close.encode("utf-8")) * 2 / 27)
                    stock_record.dif = str(float(stock_record.ema12.encode("utf-8")) - float(stock_record.ema26.encode("utf-8")))
                    stock_record.dea = str(float(pre_dea.encode("utf-8")) * 8 / 10 + float(stock_record.dif.encode("utf-8")) * 2 / 10)
                    new_json_str = json.dumps(stock_record.__dict__, encoding='UTF-8',
                                              ensure_ascii=False).encode("utf-8")
                    # 经过json.dumps和json.loads方法后的json字符串虽然内容一样，但是顺序不一样了
                    old_json_str = stock_record_tuple[0]
                    # json_str = json.dumps(stock_record.__dict__, encoding='UTF-8', ensure_ascii=False)
                    RedisUtil.redis_conn.zrem("StockRecord_"+stock_record.code.encode("utf-8"), old_json_str)
                    RedisUtil.redis_conn.zadd("StockRecord_"+stock_record.code.encode("utf-8"), stock_record.date.encode("utf-8"), new_json_str)

                    # 用于计算下一个交易日时使用
                    pre_ema12 = stock_record.ema12
                    pre_ema26 = stock_record.ema26
                    pre_dif = stock_record.dif
                    pre_dea = stock_record.dea


if __name__ == "__main__":

    print(TimeUtil.date())
